﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XrmLibrary.Adapters;
using XrmLibrary.Extensions;
using System.Threading.Tasks;

namespace XrmLibrary.Pooling
{
    public class OrganizationServicePool
    {
        private static readonly Object SyncRoot = new Object();
        private ServicePool<IOrganizationServiceAdapter> _orgServicePool;
        private static Func<IOrganizationServiceAdapter> _getOrgService;
        private readonly Int32 _serviceIndex;
        private readonly Int32 _initialServicePoolSize;

        private OrganizationServicePool(Int32 serviceIndex, Int32 initialServicePoolSize)
        {
            _serviceIndex = serviceIndex;
            _initialServicePoolSize = initialServicePoolSize;
        }

        public static OrganizationServicePool Instantiate(Int32 serviceIndex, Int32 initialServicePoolSize)
        {
            OrganizationServicePool orgServicePool = new OrganizationServicePool(serviceIndex, initialServicePoolSize);
            orgServicePool.Initialize();
            return orgServicePool;
        }

        private void Initialize()
        {
            lock (SyncRoot)
            {
                _getOrgService = () => Services.Instance.GetOrganizationService(_serviceIndex);
                _orgServicePool = new ServicePool<IOrganizationServiceAdapter>(_getOrgService);
                for (Int32 i = 0; i < _initialServicePoolSize; i++)
                {
                    AddNewServiceToPool();
                }
                //Parallel.For(0, _initialServicePoolSize, (i) => AddNewServiceToPool());
            }
        }

        private void AddNewServiceToPool()
        {
            IOrganizationServiceAdapter newService = _getOrgService.Invoke();
            newService.WhoAmI();
            _orgServicePool.PutObject(newService);
        }

        public void Refresh()
        {
            lock (SyncRoot)
            {
                _orgServicePool.Dispose();
                Initialize();
            }
        }

        public IOrganizationServiceAdapter GetService()
        {
            lock(SyncRoot)
            {
                return _orgServicePool.GetObject();
            }
        }

        public void PutService(IOrganizationServiceAdapter service)
        {
            lock (SyncRoot)
            {
                _orgServicePool.PutObject(service);
            }
        }

        public Int32 GetServiceCount()
        {
            return _orgServicePool.GetObjectCount();
        }

        public String GetServiceName()
        {
            return Services.Instance.GetConfigurationName(_serviceIndex);
        }
    }
}
